package com.xnyzc.lhy.mis.service.impl.account;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xnyzc.lhy.common.entity.Rv;
import com.xnyzc.lhy.common.exception.PangException;
import com.xnyzc.lhy.common.penum.EErrorCode;
import com.xnyzc.lhy.common.penum.account.OaDAccountAdjustmentState;
import com.xnyzc.lhy.common.penum.order.EOrderStatus;
import com.xnyzc.lhy.common.util.CheckUtil;
import com.xnyzc.lhy.common.util.DateUtil;
import com.xnyzc.lhy.common.util.IDUtil;
import com.xnyzc.lhy.common.util.TokenUtil;
import com.xnyzc.lhy.mis.common.constant.BillConstant;
import com.xnyzc.lhy.mis.entity.account.OaDAccountAdjustment;
import com.xnyzc.lhy.mis.entity.account.OaDAccountAdjustmentDetail;
import com.xnyzc.lhy.mis.entity.account.OaDAccountAdjustmentInfo;
import com.xnyzc.lhy.mis.entity.cms.config.OaSysCashWithdrawalConfig;
import com.xnyzc.lhy.mis.entity.cms.driver.DriverUserInfo;
import com.xnyzc.lhy.mis.entity.dictionaries.OaSysDict;
import com.xnyzc.lhy.mis.entity.param.account.AccountAdjustmentParam;
import com.xnyzc.lhy.mis.entity.result.cms.order.CmsOrderStatusListRes;
import com.xnyzc.lhy.mis.entity.system.OaSysGlobalConfig;
import com.xnyzc.lhy.mis.entity.user.OaDUser;
import com.xnyzc.lhy.mis.entity.wallet.OaDFreeze;
import com.xnyzc.lhy.mis.feign.finance.IDriverBillService;
import com.xnyzc.lhy.mis.mapper.dictionaries.OaSysDictMapper;
import com.xnyzc.lhy.mis.mapper.system.OaSysGlobalConfigMapper;
import com.xnyzc.lhy.mis.mapper.user.OaDUserMapper;
import com.xnyzc.lhy.mis.mapper.user.wallet.OaCWalletMapper;
import com.xnyzc.lhy.mis.entity.driver.wallet.OaDWalletRecord;
import com.xnyzc.lhy.mis.entity.param.account.OaDAccountAdjustmentDetailParam;
import com.xnyzc.lhy.mis.mapper.account.OaDAccountAdjustmentDetailMapper;
import com.xnyzc.lhy.mis.mapper.account.OaDAccountAdjustmentMapper;
import com.xnyzc.lhy.mis.mapper.driver.wallet.OaDWalletMapper;
import com.xnyzc.lhy.mis.mapper.driver.wallet.OaDWalletRecordMapper;
import com.xnyzc.lhy.mis.mapper.wallet.OaDFreezeMapper;
import com.xnyzc.lhy.mis.service.account.IOaDAccountAdjustmentDetailService;
import com.xnyzc.lhy.mis.service.account.IOaDAccountAdjustmentService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xnyzc.lhy.mis.service.cms.config.IOaSysCashWithdrawalConfigService;
import com.xnyzc.lhy.order.entity.bill.OaDBill;
import com.xnyzc.lhy.mis.entity.driver.wallet.OaDWallet;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.map.HashedMap;
import org.apache.http.client.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.*;

import static com.xnyzc.lhy.common.util.CheckUtil.objIsNotEmpty;


/**
 * <p>
 * 司机账户调整表 服务实现类
 * </p>
 *
 * @author cuichaoqun
 * @since 2019-10-19
 */
@Service
@Slf4j
public class OaDAccountAdjustmentServiceImpl
    extends ServiceImpl<OaDAccountAdjustmentMapper, OaDAccountAdjustment>
    implements IOaDAccountAdjustmentService
{
    @Autowired
    OaDAccountAdjustmentMapper oaDAccountAdjustmentMapper;

    @Autowired
    OaDAccountAdjustmentDetailMapper oaDAccountAdjustmentDetailMapper;

    @Autowired
    IOaDAccountAdjustmentDetailService oaDAccountAdjustmentDetailService;

    @Autowired
    OaDWalletMapper oaDWalletMapper;

    @Autowired
    OaDWalletRecordMapper oaDWalletRecordMapper;

    @Autowired
    OaCWalletMapper oaCWalletMapper;

    @Autowired
    private OaSysDictMapper oaSysDictMapper;

    @Autowired
    private OaDUserMapper oaDUserMapper;

    @Autowired
    private OaSysGlobalConfigMapper sysGlobalConfigMapper;

    @Autowired
    private IDriverBillService iDriverBillService;

    @Autowired
    private IOaSysCashWithdrawalConfigService iOaSysCashWithdrawalConfigService;

    @Autowired
    private OaDFreezeMapper oaDFreezeMapper;

    /**
     * 获取审核状态字典列表
     *
     * @return 审核状态字典列表
     */
    @Override
    public Rv queryAdjustmentStatue()
    {
        Long sysUserId = TokenUtil.getTokenUserId();
        List<String> dataScope = TokenUtil.getRoleDataScope();
        if (CheckUtil.objIsEmpty(dataScope) || CheckUtil.objIsEmpty(sysUserId))
        {
            throw PangException.create(EErrorCode.missingArg);
        }

        //获取审核状态字典
        QueryWrapper queryWrapper = new QueryWrapper();

        queryWrapper.eq(OaSysDict.TYPE, OaDAccountAdjustment.ADJUSTMENT_STATUS);
        List<OaSysDict> list = oaSysDictMapper.selectList(queryWrapper);

        //返回查询结果
        return Rv.wrap(list);
    }

    @Override
    @Transactional
    public Rv insertIOaDAccountAdjustment(
        OaDAccountAdjustmentDetailParam oaDAccountAdjustmentDetailParam)
    {
        Date date = new Date();
        if (oaDAccountAdjustmentDetailParam != null)
        {
            List<OaDAccountAdjustmentDetail> oaDAccountAdjustmentDetails = oaDAccountAdjustmentDetailParam.getOaDAccountAdjustmentDetailList();
            if (oaDAccountAdjustmentDetails.size() > 0)
            {
                if (this.validateDrivers(oaDAccountAdjustmentDetails))
                {
                    OaDAccountAdjustment oaDAccountAdjustment = new OaDAccountAdjustment();
                    Long id = IDUtil.nextId();
                    oaDAccountAdjustment.setAdjustmentId(id);
                    oaDAccountAdjustment.setAdjustmentStatus(0);
                    Long sysUserId = TokenUtil.getTokenUserId();
                    oaDAccountAdjustment.setCreateUser(sysUserId);
                    oaDAccountAdjustment.setCreateTime(date);
                    oaDAccountAdjustment.setUpdateTime(date);
                    oaDAccountAdjustment.setOssFileId(
                        oaDAccountAdjustmentDetailParam.getOssFileId());
                    oaDAccountAdjustment.setAdjustmentSerialNo(
                        "SJZHTZ" + DateUtil.getDateDay().replaceAll("-", "") +
                        UUID.randomUUID().toString().replace("-", "").substring(0, 9));
                    oaDAccountAdjustmentMapper.insert(oaDAccountAdjustment);
                    for (OaDAccountAdjustmentDetail oaDAccountAdjustmentDetail : oaDAccountAdjustmentDetails)
                    {
                        Long detailId = IDUtil.nextId();
                        oaDAccountAdjustmentDetail.setDetailId(detailId);
                        oaDAccountAdjustmentDetail.setCreateUser(sysUserId);
                        oaDAccountAdjustmentDetail.setCreateTime(date);
                        oaDAccountAdjustmentDetail.setUpdateTime(date);
                        oaDAccountAdjustmentDetail.setAdjustmentId(
                            oaDAccountAdjustment.getAdjustmentId());
                        // oaDAccountAdjustmentDetailMapper.insert(oaDAccountAdjustmentDetail);
                    }
                    // 批量插入
                    oaDAccountAdjustmentDetailService.saveBatch(oaDAccountAdjustmentDetails);
                }
                else
                {
                    return Rv.error(EErrorCode.driverAccountAdjustmentDriverFailed);
                }
            }
            else
            {
                return Rv.wrap(EErrorCode.missingArg);
            }
        }
        else
        {
            return Rv.wrap(EErrorCode.missingArg);
        }
        return Rv.wrap(EErrorCode.success);
    }

    private boolean validateDrivers(List<OaDAccountAdjustmentDetail> oaDAccountAdjustmentDetails)
    {
        boolean flag = true;
        for (OaDAccountAdjustmentDetail oaDAccountAdjustmentDetail : oaDAccountAdjustmentDetails)
        {
            QueryWrapper<OaDUser> deriverWrapper = new QueryWrapper<OaDUser>();
            deriverWrapper.eq("driver_id", oaDAccountAdjustmentDetail.getDriverId());
            deriverWrapper.eq("driver_name", oaDAccountAdjustmentDetail.getDriverName());
            if(oaDUserMapper.selectOne(deriverWrapper) == null)
            {
                flag = false;
                break;
            }
        }
        return flag;
    }

    @Override
    @Transactional
    public Rv updateIOaDAccountAdjustmentStatue(Integer adjustmentState, Long adjustmentId)
    {
        Integer result = null;
        Date date = new Date();
        QueryWrapper<OaDAccountAdjustment> oaDAccountAdjustmentQueryWrapper = new QueryWrapper<>();
        oaDAccountAdjustmentQueryWrapper.eq(OaDAccountAdjustment.ADJUSTMENT_ID, adjustmentId);
        oaDAccountAdjustmentQueryWrapper.eq(OaDAccountAdjustment.DELETED, 0);
        OaDAccountAdjustment oaDAccountAdjustment = oaDAccountAdjustmentMapper.selectOne(
                oaDAccountAdjustmentQueryWrapper);
        if (oaDAccountAdjustment != null && adjustmentState != null &&
                adjustmentState.equals(OaDAccountAdjustmentState.adjustmentState2.getValue()))
        {
            oaDAccountAdjustment.setAdjustmentStatus(adjustmentState);
            result = oaDAccountAdjustmentMapper.updateById(oaDAccountAdjustment);
            if (result != 1)
            {
                return Rv.wrap(EErrorCode.driverAccountModificationReviewStatusFailed);
            }
        }
        else if (oaDAccountAdjustment != null && adjustmentState != null &&
                adjustmentState.equals(OaDAccountAdjustmentState.adjustmentState1.getValue()))
        {
            //根据账户调整表 查询  账户调整明细表
            oaDAccountAdjustment.setAdjustmentStatus(adjustmentState);
            result = oaDAccountAdjustmentMapper.updateById(oaDAccountAdjustment);
            if (result != 1)
            {
                return Rv.wrap(EErrorCode.driverAccountModificationReviewStatusFailed);
            }

            //获取账户调整明细
            List<OaDAccountAdjustmentDetail> oaDAccountAdjustmentDetails = oaDAccountAdjustmentDetailMapper.selectList(
                    Wrappers.<OaDAccountAdjustmentDetail>lambdaQuery()
                            .eq(OaDAccountAdjustmentDetail::getAdjustmentId,
                                    oaDAccountAdjustment.getAdjustmentId())
                            .eq(OaDAccountAdjustmentDetail::getDeleted, 0));
            if (oaDAccountAdjustmentDetails.size() > 0)
            {
                StringBuilder amountRemark = null;
                for (OaDAccountAdjustmentDetail oaDAccountAdjustmentDetail : oaDAccountAdjustmentDetails)
                {
                    //amountRemark 费用说明
                    amountRemark = new StringBuilder();
                    amountRemark.append("账户调整审核人")
                            .append(oaDAccountAdjustment.getAdjustmentApprovalUser())
                            .append("向司机")
                            .append(oaDAccountAdjustmentDetail.getDriverId())
                            .append("发起司机账户调整");
                    int num = oaDAccountAdjustmentDetail.getAmount().signum();
                    OaDWallet oaDWallet = oaDWalletMapper.selectOne(
                            Wrappers.<OaDWallet>lambdaQuery()
                                    .eq(OaDWallet::getDriverId, oaDAccountAdjustmentDetail.getDriverId())
                    );
                    if (oaDWallet != null)
                    {
                        //钱包余额 = 可提现金额 + 冻结金额，如果操作了冻结金额或者可提现金额，都要同步修改钱包余额
                        //向上的账户调整，即为向“冻结余额”内打钱
                        //向下的账户调整，即为从“可提现金额”内扣钱，不足时从“冻结余额”内扣钱
                        if (num > 0 && oaDWallet != null)
                        {
                            amountRemark.append(
                                    "向“冻结余额”内打" + oaDAccountAdjustmentDetail.getAmount() + "元，");
                            oaDWallet.setWalletBalance(oaDWallet.getWalletBalance().add(
                                    oaDAccountAdjustmentDetail.getAmount()));
                            oaDWallet.setFrozenBalance(oaDWallet.getFrozenBalance().add(
                                    oaDAccountAdjustmentDetail.getAmount()));
                            oaDWalletMapper.updateById(oaDWallet);
                            amountRemark.append("现余额")
                                    .append(oaDWallet.getCashBalance());

                            //创建冻结金额记录表数据
                            this.saveFreezeBalance(oaDWallet.getDriverId(), oaDAccountAdjustmentDetail.getAmount());
                        }
                        else if (num < 0 && oaDWallet != null)
                        {
                            BigDecimal balance = oaDWallet.getCashBalance().add(
                                    oaDAccountAdjustmentDetail.getAmount());

                            oaDWallet.setWalletBalance(oaDWallet.getWalletBalance().add(
                                    oaDAccountAdjustmentDetail.getAmount()));
                            int number = balance.signum();
                            if (number >= 0)
                            {
                                amountRemark.append(
                                        "从“可提现金额”内扣" + oaDAccountAdjustmentDetail.getAmount() + "元，");
                                oaDWallet.setCashBalance(balance);
                            }
                            else
                            {
                                oaDWallet.setCashBalance(new BigDecimal(0));
                                amountRemark.append(
                                        "从“可提现金额”内扣" + oaDWallet.getCashBalance() + "元，");
                                amountRemark.append("从“冻结余额”内扣" + balance + "元，");
                                oaDWallet.setFrozenBalance(
                                        oaDWallet.getFrozenBalance().add(balance));

                                //创建冻结金额记录表数据
                                this.saveFreezeBalance(oaDWallet.getDriverId(), balance);
                            }
                            oaDWalletMapper.updateById(oaDWallet);
                            amountRemark.append("现余额")
                                    .append(oaDWallet.getCashBalance());
                        }
                        //添加钱包明细表   类型10为司机账户调整   交易流水号规则 SJZHTZ + YYYYMMdd + 十位随机数
                        OaDWalletRecord oaDWalletRecord = new OaDWalletRecord();
                        oaDWalletRecord.setRecordId(IDUtil.nextId());
                        oaDWalletRecord.setDriverId(oaDWallet.getDriverId());
                        oaDWalletRecord.setAmount(oaDAccountAdjustmentDetail.getAmount());
                        oaDWalletRecord.setRecordType(10);
                        oaDWalletRecord.setTransactionTime(date);
                        oaDWalletRecord.setTransactionSerialNo(
                                "SJZHTZ" + DateUtil.getDateDay().replaceAll("-", "") +
                                        UUID.randomUUID().toString().replace("-", "").substring(0, 9));
                        oaDWalletRecord.setAmountRemark(amountRemark.toString());
                        oaDWalletRecord.setTag("lhy");
                        oaDWalletRecord.setCreateUser(oaDAccountAdjustment.getCreateUser());
                        oaDWalletRecord.setCreateTime(date);
                        oaDWalletRecord.setUpdateUser(oaDAccountAdjustment.getCreateUser());
                        oaDWalletRecord.setUpdateTime(date);
                        oaDWalletRecordMapper.insert(oaDWalletRecord);

                        //创建司机流水
                        this.saveOaDBill("", oaDAccountAdjustmentDetail.getAmount(), oaDWallet.getDriverId());
                    }
                }
            }
        }
        else
        {
            return Rv.wrap(EErrorCode.unData);
        }
        return Rv.wrap(EErrorCode.success);
    }

    /**
     * 创建司机冻结记录
     * @param driverId 司机ID
     * @param freezeAmount 冻结金额
     */
    @Override
    public void saveFreezeBalance(Long driverId, BigDecimal freezeAmount){
        OaDFreeze oaDFreeze = new OaDFreeze();

        oaDFreeze.setFreezeId(IDUtil.nextId());
        oaDFreeze.setFreezeAmount(freezeAmount);
        oaDFreeze.setDriverId(driverId);
        oaDFreeze.setBillTypeDesc("1");
        oaDFreeze.setTag(TokenUtil.getTag());

        OaSysCashWithdrawalConfig config = iOaSysCashWithdrawalConfigService.getCashWithdrawalConfig(oaDFreeze.getDriverId());
        if(CheckUtil.objIsEmpty(config)){
            throw PangException.create(EErrorCode.notConfigured);
        }
        Integer freezePeriod = config.getFreezePeriod();

        Date date = new Date();

        try {
            // 设置冻结期 ( 若设置为1天，则代表隔一天解冻，不是明天解冻而是后天解冻 )
            oaDFreeze.setFreezeDate(DateUtil.dateAddDays(date, freezePeriod + 1));
        } catch (Exception e) {
            log.error(e.getMessage());
            log.error("日期转换错误，检查参数：天数:{}，日期：{}", freezePeriod, date);
            throw PangException.create(EErrorCode.dataParseError);
        }

        oaDFreeze.setCreateUser(oaDFreeze.getDriverId());
        oaDFreeze.setCreateTime(date);
        oaDFreeze.setUpdateUser(oaDFreeze.getDriverId());
        oaDFreeze.setUpdateTime(date);

        oaDFreezeMapper.insert(oaDFreeze);
    }

    /**
     * 创建司机账单流水
     *
     * @return
     */
    @Override
    public void saveOaDBill(String orderNo, BigDecimal drawFee, Long driverId) {
        try {
            Integer billType = 0;
            String billTypeDesc = "";

            int compare = drawFee.compareTo(BigDecimal.ZERO);
            if (compare > 0) {
                billType = BillConstant.INCOME;
                billTypeDesc = BillConstant.accountAdjustmentIn;
            } else if (compare < 0) {
                billType = BillConstant.EXPAND;
                billTypeDesc = BillConstant.accountAdjustmentOut;

                //负数创建正数流水、通过状态判断正负流水
                drawFee = drawFee.negate();
            }else{
                return;
            }

            OaDBill oaDBill = new OaDBill();
            oaDBill.setDriverId(driverId);
            oaDBill.setOrderNumber(orderNo);
            oaDBill.setBillAmount(drawFee);
            oaDBill.setBillType(billType);
            oaDBill.setBillTypeDesc(billTypeDesc);
            oaDBill.setLogonTag(BillConstant.LogonTag);
            oaDBill.setTag(TokenUtil.getTag());

            iDriverBillService.saveDriverBill(oaDBill);
        } catch (Exception ex) {
            log.info("创建司机流水失败");
        }
    }

    /**
     * 创建司机账单流水：活动奖励
     *
     * @return
     */
    @Override
    public void saveActivityOaDBill(String orderNo, BigDecimal drawFee, Long driverId) {
        try {
            Integer billType = 0;
            String billTypeDesc = "";

            int compare = drawFee.compareTo(BigDecimal.ZERO);
            if (compare > 0) {
                billType = BillConstant.INCOME;
                billTypeDesc = BillConstant.activityIn;
            } else if (compare < 0) {
                billType = BillConstant.EXPAND;
                billTypeDesc = BillConstant.activityIn;

                //负数创建正数流水、通过状态判断正负流水
                drawFee = drawFee.negate();
            }else{
                return;
            }

            OaDBill oaDBill = new OaDBill();
            oaDBill.setDriverId(driverId);
            oaDBill.setOrderNumber(orderNo);
            oaDBill.setBillAmount(drawFee);
            oaDBill.setBillType(billType);
            oaDBill.setBillTypeDesc(billTypeDesc);
            oaDBill.setLogonTag(BillConstant.LogonTag);
            oaDBill.setTag(TokenUtil.getTag());

            iDriverBillService.saveDriverBill(oaDBill);
        } catch (Exception ex) {
            log.info("创建司机流水失败");
        }
    }

    @Override
    public Rv deleteDateIOaDAccountAdjustment(Long adjustmentId)
    {
        Integer result = oaDAccountAdjustmentMapper.deleteById(adjustmentId);
        if (result.equals(1))
        {
            return Rv.wrap(EErrorCode.success);
        }
        else
        {
            return Rv.wrap(EErrorCode.beUsed);
        }

    }

    @Override
    public Rv queryDateIOaDAccountAdjustment(AccountAdjustmentParam accountAdjustmentParam)
    {
        try
        {
            IPage iPage = new Page();
            iPage.setSize(accountAdjustmentParam.getPageSize());
            iPage.setCurrent(accountAdjustmentParam.getCurrent());
            List<OaDAccountAdjustmentInfo> oaDAccountAdjustmentInfos = oaDAccountAdjustmentMapper.queryDateIOaDAccountAdjustment(
                iPage, accountAdjustmentParam.getAdjustmentSerialNo(),
                accountAdjustmentParam.getAdjustmentState(),
                accountAdjustmentParam.getCreateUser());

            for (OaDAccountAdjustmentInfo oaDAccountAdjustmentInfo : oaDAccountAdjustmentInfos)
            {
                SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                oaDAccountAdjustmentInfo.setCreateTime(
                    formatter.format(oaDAccountAdjustmentInfo.getParseDate()));
            }

            iPage.setRecords(oaDAccountAdjustmentInfos);
            return Rv.wrap(EErrorCode.success, iPage);
        }
        catch (Exception e)
        {
            e.printStackTrace();
            return Rv.wrap(EErrorCode.dataParseError);
        }

    }

    /**
     * 下载账户调整模板
     * @return
     */
    @Override
    public Rv getAccountAdjustmentDownloadTemplate() {
        List<OaSysGlobalConfig> oaSysGlobalConfigs = sysGlobalConfigMapper.selectList(null);
        if (CheckUtil.objIsEmpty(oaSysGlobalConfigs)) {
            return Rv.wrap(EErrorCode.unData);
        }
        OaSysGlobalConfig config = oaSysGlobalConfigs.get(0);
        Map<String, String> map = new HashMap<>();
        map.put("id", config.getAccountAdjustmentFileId());
        return Rv.wrap(EErrorCode.success, map);
    }
}
